#include "stdafx.h"

#include "EngineTests.h"


 // move generation
///////////////////////////////////////////////////////////

TSingleMove testedSingleMove;

void inline ClearTestedSingleMove()
{
	memset( &testedSingleMove, 0, sizeof( TSingleMove ) );
}

 // White Man Moves
////////////////////////////////////////////////////////////

bool CheckWhiteManJumps(TGameBoard board, SMoveAnalysis* pMoveAnalysis, BYTE dwPos, BYTE dwSrc)
{
	bool bJumpFound = false;

	if( IS_BLACKFIGURE(board[dwSrc+4]) && IS_EMPTY(board[dwSrc+8]))
	{
		register BYTE dwNewPos = dwSrc + 8;
		testedSingleMove.MovePositions[dwPos] =dwNewPos;
		testedSingleMove.RemovePositions[dwPos - 1] = dwSrc + 4;
		testedSingleMove.RemovedFigures[dwPos - 1] = board[dwSrc + 4];

		if(CheckWhiteManJumps(board, pMoveAnalysis, dwPos + 1, dwNewPos) == false)
		{
			pMoveAnalysis->AddMove(&testedSingleMove, true);
		}
		testedSingleMove.MovePositions[dwPos] = 0;
		testedSingleMove.RemovePositions[dwPos - 1] = 0;
		testedSingleMove.RemovedFigures[dwPos - 1] = 0;


		bJumpFound = true;
	}

	if( IS_BLACKFIGURE(board[dwSrc+5]) && IS_EMPTY(board[dwSrc+10]))
	{
		register BYTE dwNewPos = dwSrc + 10;
		testedSingleMove.MovePositions[dwPos] = dwNewPos;
		testedSingleMove.RemovePositions[dwPos - 1] = dwSrc + 5;
		testedSingleMove.RemovedFigures[dwPos - 1] = board[dwSrc + 5];

		if(CheckWhiteManJumps(board, pMoveAnalysis, dwPos + 1, dwNewPos) == false)
		{
			pMoveAnalysis->AddMove(&testedSingleMove, true);
		}
		testedSingleMove.MovePositions[dwPos] = 0;
		testedSingleMove.RemovePositions[dwPos - 1] = 0;
		testedSingleMove.RemovedFigures[dwPos - 1] = 0;


		bJumpFound = true;
	}

	return bJumpFound;
}

void CheckWhiteManMoves(TGameBoard board, SMoveAnalysis* pMoveAnalysis, BYTE dwSrc)
{
	register BYTE dwTarget = dwSrc + 4;
	if( IS_EMPTY(board[dwTarget]))
	{
		pMoveAnalysis->AddMove(dwSrc, dwTarget, false);
	}
	dwTarget = dwSrc + 5;
	if( IS_EMPTY(board[dwTarget] ))
	{
		pMoveAnalysis->AddMove(dwSrc, dwTarget, false);
	}
}

bool GenerateWhiteManJumps(TGameBoard board, SMoveAnalysis* pMoveAnalysis)
{
	bool bJumpFound = false;

	for(int index = 0; index < GAMEBOARD_SIZE; index++)
	{
		register BYTE dwSrcField = board[index];
		if(dwSrcField == WHITE_MAN)
		{
			ClearTestedSingleMove();
			testedSingleMove.MovePositions[0] = index;
			if(CheckWhiteManJumps(board, pMoveAnalysis, 1, index) == true)
				bJumpFound = true;
		}
	}

	return bJumpFound;
}


void GenerateWhiteManMoves(TGameBoard board, SMoveAnalysis* pMoveAnalysis)
{
	for(int index = 0; index < GAMEBOARD_SIZE; index++)
	{
		register BYTE dwSrcField = board[index];
		if(dwSrcField == WHITE_MAN)
		{
			CheckWhiteManMoves(board, pMoveAnalysis, index);
		}
	}
}

 // Black Man Moves
////////////////////////////////////////////////////////////

bool CheckBlackManJumps(TGameBoard board, SMoveAnalysis* pMoveAnalysis, BYTE dwPos, BYTE dwSrc)
{
	bool bJumpFound = false;

	if( IS_WHITEFIGURE(board[dwSrc-4]) && IS_EMPTY(board[dwSrc-8]))
	{
		register BYTE dwNewPos = dwSrc - 8;
		testedSingleMove.MovePositions[dwPos] = dwNewPos;
		testedSingleMove.RemovePositions[dwPos - 1] = dwSrc - 4;
		testedSingleMove.RemovedFigures[dwPos - 1] = board[dwSrc - 4];

		if(CheckBlackManJumps(board, pMoveAnalysis, dwPos + 1, dwNewPos) == false)
		{
			pMoveAnalysis->AddMove(&testedSingleMove, true);
		}
		testedSingleMove.MovePositions[dwPos] = 0;
		testedSingleMove.RemovePositions[dwPos - 1] = 0;
		testedSingleMove.RemovedFigures[dwPos - 1] = 0;


		bJumpFound = true;
	}

	if( IS_WHITEFIGURE(board[dwSrc-5]) && IS_EMPTY(board[dwSrc-10]))
	{
		register BYTE dwNewPos = dwSrc - 10;
		testedSingleMove.MovePositions[dwPos] = dwNewPos;
		testedSingleMove.RemovePositions[dwPos - 1] = dwSrc - 5;
		testedSingleMove.RemovedFigures[dwPos - 1] = board[dwSrc - 5];

		if(CheckBlackManJumps(board, pMoveAnalysis, dwPos + 1, dwNewPos) == false)
		{
			pMoveAnalysis->AddMove(&testedSingleMove, true);
		}
		testedSingleMove.MovePositions[dwPos] = 0;
		testedSingleMove.RemovePositions[dwPos - 1] = 0;
		testedSingleMove.RemovedFigures[dwPos - 1] = 0;

		bJumpFound = true;
	}

	return bJumpFound;
}

void CheckBlackManMoves(TGameBoard board, SMoveAnalysis* pMoveAnalysis, BYTE dwSrc)
{
	register BYTE dwTarget = dwSrc - 4;
	if( IS_EMPTY(board[dwTarget]))
	{
		pMoveAnalysis->AddMove(dwSrc, dwTarget,  false );
	}
	dwTarget = dwSrc - 5;
	if( IS_EMPTY(board[dwTarget] ))
	{
		pMoveAnalysis->AddMove(dwSrc, dwTarget, false );
	}
}

bool GenerateBlackManJumps(TGameBoard board, SMoveAnalysis* pMoveAnalysis)
{
	bool bJumpFound = false;

	for(int index = 0; index < GAMEBOARD_SIZE; index++)
	{
		register BYTE dwSrcField = board[index];
		if(dwSrcField == BLACK_MAN)
		{
			ClearTestedSingleMove();
			testedSingleMove.MovePositions[0] = index;
			if(CheckBlackManJumps(board, pMoveAnalysis, 1, index) == true)
				bJumpFound = true;
		}
	}

	return bJumpFound;
}


void GenerateBlackManMoves(TGameBoard board, SMoveAnalysis* pMoveAnalysis)
{
	for(int index = 0; index < GAMEBOARD_SIZE; index++)
	{
		register BYTE dwSrcField = board[index];
		if(dwSrcField == BLACK_MAN)
		{
			CheckBlackManMoves(board, pMoveAnalysis, index);
		}
	}
}

 // King Jumps
//////////////////////////////////////////////////////////////////////////////

bool CheckKingJumps(TGameBoard board, SMoveAnalysis* pMoveAnalysis, BYTE dwSrc, BYTE dwPos, bool bWhite, int ignoredDirection);

bool CheckKingJumpsInDirection(TGameBoard board, SMoveAnalysis* pMoveAnalysis, BYTE dwSrc, BYTE dwPos, bool bWhite, 
							int direction)
{
	BYTE dwCurPos = dwSrc + direction;
	while( board[dwCurPos] != BORDER )
	{
		BYTE dwField = board[dwCurPos];
		if( IS_EMPTY( dwField ) == true )
		{
			dwCurPos = dwCurPos + direction;
		}
		else
		{
			if( (bWhite == true && IS_BLACKFIGURE(dwField)) || (bWhite == false && IS_WHITEFIGURE(dwField)) )
			{
				register BYTE dwJumpPos = dwCurPos;

				dwCurPos = dwCurPos + direction;
				dwField = board[dwCurPos];
				if( IS_EMPTY(dwField) == true)
				{
					BYTE dwJumpedFigure = board[ dwJumpPos ];
					testedSingleMove.RemovePositions[dwPos - 1] = dwJumpPos;
					testedSingleMove.RemovedFigures[dwPos - 1] = dwJumpedFigure;

					board[dwJumpPos] = 0;
					
					BYTE dwFields[MAX_MOVE_STEPS + 1];
					memset(dwFields, 0, sizeof(BYTE)*(MAX_MOVE_STEPS + 1));
					int fieldIndex = 0;

					bool bMultipleJumpFound = false;

					while(IS_EMPTY(board[dwCurPos]))
					{
						testedSingleMove.MovePositions[dwPos] = dwCurPos; // record new move
						board[dwCurPos] = board[dwSrc];
						board[dwSrc] = 0;
						// continue with check of multiple jump
						if(CheckKingJumps(board, pMoveAnalysis, dwCurPos, dwPos + 1, bWhite, OPPOSITE_DIRECTION(direction)) == true)
						{
							bMultipleJumpFound = true;
						}

						board[dwSrc] = board[dwCurPos];
						board[dwCurPos] = 0;					
						dwFields[fieldIndex++] = dwCurPos;
						dwCurPos += direction;
					} // while


					if(bMultipleJumpFound == false)
					{
						int index = 0;
						while(dwFields[index])
						{
							testedSingleMove.MovePositions[dwPos] = dwFields[index++];
							// no addition jump, record it
							pMoveAnalysis->AddMove(&testedSingleMove, true);
						} // while
					} // if


					board[dwJumpPos] = dwJumpedFigure;
					testedSingleMove.MovePositions[dwPos] = 0;
					testedSingleMove.RemovePositions[dwPos - 1] = 0;
					testedSingleMove.RemovedFigures[dwPos - 1] = 0;


					return true;
				}
				else return false;
			}
			else return false; // figure of the same color
		}
	}

	return false;
}

bool CheckKingJumps(TGameBoard board, SMoveAnalysis* pMoveAnalysis, BYTE dwSrc, BYTE dwPos, bool bWhite, int ignoredDirection)
{
	bool bJumpFound = false;
	if(ignoredDirection != -4)
	{
		if(CheckKingJumpsInDirection(board, pMoveAnalysis, dwSrc, dwPos, bWhite, -4))
			bJumpFound = true;
	}
	if(ignoredDirection != -5)
	{
		if(CheckKingJumpsInDirection(board, pMoveAnalysis, dwSrc, dwPos, bWhite, -5))
			bJumpFound = true;
	}
	if(ignoredDirection != +4)
	{
		if(CheckKingJumpsInDirection(board, pMoveAnalysis, dwSrc, dwPos, bWhite, +4))
			bJumpFound = true;
	}
	if(ignoredDirection != +5)
	{
		if(CheckKingJumpsInDirection(board, pMoveAnalysis, dwSrc, dwPos, bWhite, +5))
			bJumpFound = true;
	}

	return bJumpFound;
}

void CheckKingMovesInDirection(TGameBoard board, SMoveAnalysis* pMoveAnalysis, BYTE dwSrc, int direction)
{
	BYTE dwCurPos = dwSrc + direction;
	while(board[dwCurPos] != BORDER)
	{
		BYTE dwField = board[dwCurPos];
		if( IS_EMPTY( dwField ) == true )
		{
			pMoveAnalysis->AddMove(dwSrc, dwCurPos, false);
			dwCurPos = dwCurPos + direction;
		}
		else return;
	}
}

void CheckKingMoves(TGameBoard board, SMoveAnalysis* pMoveAnalysis, BYTE dwSrc)
{
	CheckKingMovesInDirection(board, pMoveAnalysis, dwSrc, -4);
	CheckKingMovesInDirection(board, pMoveAnalysis, dwSrc, -5);
	CheckKingMovesInDirection(board, pMoveAnalysis, dwSrc, +4);
	CheckKingMovesInDirection(board, pMoveAnalysis, dwSrc, +5);
}

bool GenerateKingJumps(TGameBoard board, SMoveAnalysis* pMoveAnalysis, bool bWhite)
{
	bool bJumpFound = false;
	register BYTE dwFigure = bWhite == true ? WHITE_King : BLACK_King;

	for(int index = 0; index < GAMEBOARD_SIZE; index++)
	{
		register BYTE dwSrcField = board[index];
		if(dwSrcField == dwFigure)
		{
			ClearTestedSingleMove();
			testedSingleMove.MovePositions[0] = index;
			if(CheckKingJumps(board, pMoveAnalysis, index, 1, bWhite, 0) == true)
				bJumpFound = true;
		}
	}

	return bJumpFound;
}


void GenerateKingMoves(TGameBoard board, SMoveAnalysis* pMoveAnalysis, bool bWhite)
{
	register BYTE dwFigure = bWhite == true ? WHITE_King : BLACK_King;

	for(int index = 0; index < GAMEBOARD_SIZE; index++)
	{
		register BYTE dwSrcField = board[index];
		if(dwSrcField == dwFigure)
		{
			CheckKingMoves(board, pMoveAnalysis, index);
		}
	}
}

 // Main generating function
/////////////////////////////////////////////////////////////////////////////////////////////


void GenerateMoves(TGameBoard board, SMoveAnalysis* pMoveAnalysis, bool bWhite)
{
	// first check King jumps precedence
	if(GenerateKingJumps(board, pMoveAnalysis, bWhite) == true)
	{
		pMoveAnalysis->BuildOrderOfMoves();
		return;
	}

	// then check man jumps precedence
	if(bWhite == true)
	{
		if(GenerateWhiteManJumps(board, pMoveAnalysis) == true)
		{
			pMoveAnalysis->BuildOrderOfMoves();
			return;	
		}
	}
	else
	{
		if(GenerateBlackManJumps(board, pMoveAnalysis) == true)
		{
			pMoveAnalysis->BuildOrderOfMoves();
			return;	
		}
	}

	// then King steps
	GenerateKingMoves(board, pMoveAnalysis, bWhite);

	// finally move steps
	if(bWhite == true)
	{
		GenerateWhiteManMoves(board, pMoveAnalysis);
	}
	else
	{
		GenerateBlackManMoves(board, pMoveAnalysis);
	}

	pMoveAnalysis->BuildOrderOfMoves();
}

